Constraining Delimited Control with Contracts

نویسندگان

  • Asumu Takikawa
  • T. Stephen Strickland
  • Sam Tobin-Hochstadt
چکیده

Most programming languages provide abstractions for non-local control flow and access to the stack by using continuations, coroutines, or generators. However, their unrestricted use breaks the local reasoning capability of a programmer. Gradual typing exacerbates this problem because typed and untyped code co-exist. We present a contract system capable of protecting code from control flow and stack manipulations by unknown components. We use these contracts to support a gradual type system, and we prove that the resulting system cannot blame typed components for errors. 1 Ubiquitous Continuations Delimited continuations [6, 10, 12, 18, 19, 26, 27] enable the expression of many useful programming constructs such as coroutines, engines, and exceptions as libraries. Their expressive power stems from three key operations on the control stack: (1) marking a stack frame with a prompt; (2) jumping to a marked frame, discarding the context in between; and (3) re-attaching the slice of the control stack that the jump discarded. Continuations are not the only operations that manipulate the stack. In particular, continuation marks [4] provide the ability to (4) annotate a stack frame with data that can be dynamically accessed and updated from subsequent frames. They are used to implement features like general stack inspection for debugging, dynamic binding, and aspect-oriented programming as libraries [4, 22, 23]. Many dynamically-typed languages support delimited continuations and related control operators such as coroutines or generators [15, 20], and some also support continuation marks [5, 15]. Their lack of static typing, however, implies that a programmer could easily misuse manipulations of the stack to jump to the wrong place or annotate a frame with the wrong kind of data. Gradual typing addresses just these kinds of problems. Gradually typed languages allow programmers to type parts of their programs statically but leave other parts untyped. Even better, they provide strong dynamic guarantees about the safety of the combination of typed and untyped code [24, 32]. In particular, a gradually typed language does not allow untyped code to cause a run-time violation of the type invariants in the typed code. Unfortunately, naïvely combining delimited continuations, continuation marks, and gradual typing fails to maintain the benefits of gradual typing. The numerous type systems proposed for delimited continuations [2, 6, 11, 18, 20, 21] can prevent an ill-typed ? Supported in part by NSF CRI-0855140, SHF-1064922, CCF-0915978, the Mozilla Foundation, and the DARPA CRASH program re-attachment of a continuation or an ill-typed continuation jump. However, these type systems alone are not sufficient for gradual typing, because of the need for dynamic enforcement. Ordinarily, gradual type systems dynamically protect a typed component from its untyped context with a contract [14] that monitors the flow of values across the boundary [31]. Continuations, however, allow an untyped component to bypass the contract protection at the component boundary by jumping over the contract. After the jump, the untyped code could arrive in the middle of a typed component on the control stack and deliver an ill-typed value. Similarly, a continuation mark allows untyped code to update a stack annotation in typed code with an ill-typed value. In other words, continuations and continuation marks establish illicit communication channels between components. For the invariants of the typed language to hold, these channels require additional protection [9]. In this paper, we equip a gradually typed language with typed delimited control operators and continuation marks while maintaining the soundness of the entire system. To support this gradual type system, we introduce and formalize control contracts that mediate continuation jumps between prompts and their clients. We implement them in the Racket programming language [15] using control chaperones based on Strickland et al. [28]’s chaperone framework. Control chaperones allow a programmer to redirect communication between a prompt and a corresponding jump, inserting contract checks in between. For continuation marks, we offer an analogous pair of continuation mark key contracts and continuation mark key chaperones. We also prove a soundness theorem for the combined language using Dimoulas et al’s complete monitoring [9] technique. The key idea is to split a program into typed and untyped components via ownership annotations on values. Using these annotations, we impose a single owner policy which ensures that, at any given point, all of the values in the program are owned only by the typed or untyped portion of the program. Components may transfer ownership of a value only through the use of a contract, guaranteeing that no value changes hands without being checked. We prove that our contract system is a complete monitor and use this result to show that the gradual type system is sound. 2 Types and contracts for control operators To illustrate how delimited continuations and continuation marks cause problems for gradual typing, we present a series of examples using Sitaram’s % and fcontrol operators [26]. The following example illustrates a simple use of the % operator to install a prompt and then a use of fcontrol to jump to that prompt, aborting part of the stack. The diagram on the right depicts the control flow of the example on the stack: > (+ 2 (% (+ 1 (fcontrol 7)) (λ (nat con) (+ 1 nat)))) 10 (+ 2 []) (% [] (λ (nat con) nat)) (+ 1 []) (fcontrol 7) The evaluation of this example starts at (fcontrol 7), which immediately discards the current continuation up to the prompt (i.e., the third frame in the diagram). After discarding the continuation, fcontrol calls the handler, the λ expression argument to %, with two arguments: the value passed to fcontrol (i.e., 7) and the discarded continuation reified as a function, i.e., (λ (x) (+ 1 x)). In this case, the handler just increments the first argument by one and returns, ignoring the reified continuation. The % operator then returns the result of the handler to its context. The handler in this example is simple, but in general prompt handlers allow the programmer to specify arbitrary computations. The correspondence between the prompt handler and fcontrol matches the correspondence between exception handlers and throwing an exception [26]. In other words, continuation operators like fcontrol generalize exceptions [18]. One major difference between fcontrol and most exception interfaces is that instead of throwing the continuation away, the handler can also re-install the continuation: > (% (+ 1 (fcontrol 2)) (λ (v k) (+ v (k 8)))) 11 (% [] (λ (v k) (+ v (k 8)))) (+ 1 []) (fcontrol 2) Here the handler calls its second argument, the reified continuation, instead of ignoring it. Since the continuation is a value, the handler just calls it like any other function. In fact, the handler could choose to return the continuation or apply it multiple times. The presence of the reified continuation makes fcontrol a higher-order control operator, as opposed to exceptions, which usually only provide first-order control 2.1 Types for delimited control To implement a type system for delimited control, we must provide a means to typecheck % and fcontrol. Each handler, however, may provide a different interface to its corresponding fcontrol. That is, they expect different types of input from a jump. In order to give a precise type for these handlers, we need to keep different logical uses of fcontrol separate and type-check them separately.3 To distinguish prompts with conflicting uses, control operators in the literature often allow the programmer to annotate prompts with prompt tags [11, 16, 18, 26]. For example, an implementation of coroutines and an implementation of exceptions might both install prompts on the stack. However, the stack changes coordinated by these libraries are “logically different” [26], even if they use the same operators, and should not interfere with one another. Prompt tags also provide a convenient means to type-check separate uses of fcontrol [18]. The type of a prompt tag determines the valid types of values that an application of fcontrol can send to the corresponding prompt’s handler. The prompt tag type also specifies the return type of the handler and the prompt’s body. The % and fcontrol operators can be used with prompt tags to allow fine-grained control over what prompt is targeted: 3 A type and effect system for delimited control [2, 6] could provide more precise types. However, an effect system would require intrusive run-time monitoring to enforce with contracts. (define handler-1 (λ (v k) (string-append v "0"))) (define handler-2 (λ (v k) (k 1))) > (% (number->string (% (+ 1 (fcontrol "10" prompt-tag-1)) handler-2 prompt-tag-2)) handler-1 prompt-tag-1)

برای دانلود رایگان متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

منابع مشابه

Safe and Effective Contracts

This dissertation introduces a framework enabling the dynamic verification of expressive specifications. Inspired by formal verification methods, this framework supports assertion, framing, and separation contracts. Assertion contracts specify what code should do, whereas framing contracts specify what code must not do. Separation contracts, inspired by separation logic, combine an explicit ass...

متن کامل

The Theory and Practice of Programming Languages with Delimited Continuations

This dissertation presents a study of functional programming languages with first-class delimited continuations. We focus mainly on theoretical and practical aspects of Danvy and Filinski’s hierarchy of static delimited-control operators shiftn and resetn, and of Felleisen’s dynamic delimited-control operators control and prompt. Our study uses the traditional means of specifying semantics of f...

متن کامل

On the static and dynamic extents of delimited continuations

We show that breadth-first traversal exploits the difference between the static delimited-control operator shift (alias S) and the dynamic delimited-control operator control (alias F). For the last 15 years, this difference has been repeatedly mentioned in the literature but it has only been illustrated with one-line toy examples. Breadth-first traversal fills this vacuum. We also point out whe...

متن کامل

On the dynamic extent of delimited continuations

We show that breadth-first traversal exploits the difference between the static delimited-control operator shift (alias S) and the dynamic delimited-control operator control (alias F). For the last 15 years, this difference has been repeatedly mentioned in the literature but it has only been illustrated with one-line toy examples. Breadth-first traversal fills this vacuum. We also point out whe...

متن کامل

Contract Enforcement, Social Efficiency, and Distribution: Some Experimental Evidence

We use economic experiments to investigate how different contract enforcement regimes affect efficiency and the distribution of surplus in vertically coordinated markets where contractors have market power. We find that if a third party (e.g. government) provides full enforcement of contracts, social efficiency is enhanced. Surprisingly, we find when enforcement is completely absent, social eff...

متن کامل

ذخیره در منابع من


  با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید

عنوان ژورنال:

دوره   شماره 

صفحات  -

تاریخ انتشار 2013